package com.apache.security.filter;

import com.apache.license.filter.AbstractFilter;
import com.apache.license.validator.LicenseValidate;
import com.apache.security.SecurityConstant;
import com.apache.security.SecurityFilter;
import com.apache.security.util.SecurityHttpServletRequest;
import com.apache.security.util.SecurityHttpServletResponse;
import com.apache.security.util.XssUtil;
import com.apache.tools.StrUtil;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 *
 *
 */
public class DefaultBaseSecurityFilter extends AbstractFilter {

    private List<SecurityFilter> securityFilterList = new ArrayList<SecurityFilter>();

    private String errorPage;

    private String writeStr;

    private String encoding = null;

    public void destroy() {
        // TODO Auto-generated method stub
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        request.setCharacterEncoding(encoding);
        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            if (filterPath(httpRequest)) {
                filterChain.doFilter(request, response);
                return;
            }
            String pui = httpRequest.getRequestURI();
            if (!LicenseValidate.getInstance().isEffective()) {//初化后不在初始化
                if (pui.contains("doService.action")) {
                    filterChain.doFilter(request, response);
                }
                return;
            }
            for (int i = 0; i < securityFilterList.size(); i++) {
                securityFilterList.get(i).setErrorPage(errorPage);
                int result = securityFilterList.get(i).doFilterInvoke(httpRequest, httpResponse);
                if (0 == result)
                    return;
            }
            CookeHeader(httpRequest, httpResponse);
            filterChain.doFilter(new SecurityHttpServletRequest(httpRequest),
                    new SecurityHttpServletResponse(httpResponse));
            //			if (null != httpRequest.getSession().getAttribute("randCode")) {
            //				httpRequest.getSession().setAttribute("randCode", httpRequest.getSession().getAttribute("randCode"));
            //			}
        } else {
            filterChain.doFilter(request, response);
        }
    }

    private boolean filterPath(HttpServletRequest httpRequest) {
        String path = StrUtil.doNull(httpRequest.getContextPath(), "/");
        String pui = httpRequest.getRequestURI();
        if (pui.contains(".css") || pui.contains(".js") || pui.contains("doService.action")) {
            //如果发现是css或者js文件，直接放行
            return true;
        }
        if (pui.endsWith("/")) {
            if (pui.endsWith(path + "/")) {
                return true;
            }
        } else {
            if (pui.endsWith(path)) {
                return true;
            }
        }
        if (null != writeStr) {
            if (writeStr.contains(pui)) {
                return true;
            }
        }
        return false;
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        super.initLincense();
        initRedictWhiteList(filterConfig);
        errorPage = filterConfig.getInitParameter("errorPage");
        writeStr = filterConfig.getInitParameter("writeStr");
        this.encoding = filterConfig.getInitParameter("encoding");
        if (XssUtil.isNull(this.encoding))
            this.encoding = "UTF-8";
        try {
            initSecurityFilterList(filterConfig);
        } catch (ClassNotFoundException e) {
            throw new ServletException(e);
        } catch (InstantiationException e) {
            throw new ServletException(e);
        } catch (IllegalAccessException e) {
            throw new ServletException(e);
        }
    }

    public void initRedictWhiteList(FilterConfig filterConfig) throws ServletException {
        String list = filterConfig.getInitParameter("redirectWhiteList");
        if (StrUtil.isNull(list)) {
            return;
        }
        String[] redirectWhiteList = list.split(",");
        List<Pattern> patterns = new ArrayList<Pattern>();
        for (String str : redirectWhiteList) {
            patterns.add(Pattern.compile(str));
        }
        SecurityConstant.redirectLocationWhiteList.addAll(patterns);
    }

    private void initSecurityFilterList(FilterConfig filterConfig)
            throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String securityFilterS = filterConfig.getInitParameter("securityFilterList");
        if (StrUtil.isNull(securityFilterS)) {
            return;
        }
        String[] filterList = securityFilterS.split(",");
        for (String filter : filterList) {
            Class securityFilter = Class.forName(filter);
            SecurityFilter securityFilterInstance = (SecurityFilter) securityFilter.newInstance();
            securityFilterList.add(securityFilterInstance);
        }
    }

    /**
     * description:  修复会话cookie 中缺少HttpOnly属性漏洞
     */
    private void CookeHeader(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        if (null != cookies) {
            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.HOUR, 1);
            Date date = cal.getTime();
            Locale locale = Locale.CHINA;
            SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", locale);
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (null != cookie) {
                    if ("JSESSIONID".equalsIgnoreCase(cookie.getName())) {
                        StringBuilder builder = new StringBuilder();
                        if (cookie.getSecure())
                            builder.append("Secure;");
                        String value = cookie.getValue();
                        String path = request.getContextPath();
                        builder.append("JSESSIONID=" + value + ";");
                        builder.append("path=" + path + ";");
                        builder.append("HttpOnly;");
                        builder.append("Expires=" + sdf.format(date));
                        response.addHeader("Set-Cookie", builder.toString());
                    } else if ("apache_".equalsIgnoreCase(cookie.getName())) {
                        StringBuilder builder = new StringBuilder();
                        if (cookie.getSecure())
                            builder.append("Secure;");
                        String value = cookie.getValue();
                        String path = request.getContextPath();
                        builder.append("apache_=" + value + ";");
                        builder.append("path=" + path + ";");
                        builder.append("HttpOnly;");
                        builder.append("Expires=" + sdf.format(date));
                        response.addHeader("Set-Cookie", builder.toString());
                    }
                }
            }
        }
    }

}
